home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / elm / elm2.4 / src / fileio.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-02-08  |  12.9 KB  |  488 lines

  1.  
  2. static char rcsid[] = "@(#)$Id: fileio.c,v 5.8 1993/02/08 18:38:12 syd Exp $";
  3.  
  4. /*******************************************************************************
  5.  *  The Elm Mail System  -  $Revision: 5.8 $   $State: Exp $
  6.  *
  7.  *            Copyright (c) 1988-1992 USENET Community Trust
  8.  *            Copyright (c) 1986,1987 Dave Taylor
  9.  *******************************************************************************
  10.  * Bug reports, patches, comments, suggestions should be sent to:
  11.  *
  12.  *    Syd Weinstein, Elm Coordinator
  13.  *    elm@DSI.COM            dsinc!elm
  14.  *
  15.  *******************************************************************************
  16.  * $Log: fileio.c,v $
  17.  * Revision 5.8  1993/02/08  18:38:12  syd
  18.  * Fix to copy_file to ignore unescaped from if content_length not yet reached.
  19.  * Fixes to NLS messages match number of newlines between default messages
  20.  * and NLS messages. Also an extra ) was removed.
  21.  * From: Jan Djarv <Jan.Djarv@sa.erisoft.se>
  22.  *
  23.  * Revision 5.7  1993/01/20  03:02:19  syd
  24.  * Move string declarations to defs.h
  25.  * From: Syd
  26.  *
  27.  * Revision 5.6  1992/12/11  01:45:04  syd
  28.  * remove sys/types.h include, it is now included by defs.h
  29.  * and this routine includes defs.h or indirectly includes defs.h
  30.  * From: Syd
  31.  *
  32.  * Revision 5.5  1992/12/07  04:23:23  syd
  33.  * fix typo
  34.  * From: Syd
  35.  *
  36.  * Revision 5.4  1992/11/26  01:46:26  syd
  37.  * add Decode option to copy_message, convert copy_message to
  38.  * use bit or for options.
  39.  * From: Syd and bjoerns@stud.cs.uit.no (Bjoern Stabell)
  40.  *
  41.  * Revision 5.3  1992/11/26  00:48:34  syd
  42.  * Make it do raw(off) before final error message to
  43.  * display error message on proper screen
  44.  * From: Syd
  45.  *
  46.  * Revision 5.2  1992/11/07  20:05:52  syd
  47.  * change to use header_cmp to allow for linear white space around the colon
  48.  * From: Syd
  49.  *
  50.  * Revision 5.1  1992/10/03  22:58:40  syd
  51.  * Initial checkin as of 2.4 Release at PL0
  52.  *
  53.  *
  54.  ******************************************************************************/
  55.  
  56. /** File I/O routines, including deletion from the folder! 
  57.  
  58. **/
  59.  
  60. #include "headers.h"
  61. #include "s_elm.h"
  62. #include <sys/stat.h>
  63. #include <ctype.h>
  64. #include <errno.h>
  65.  
  66. #ifdef BSD
  67. #undef tolower
  68. #endif
  69.  
  70. extern int errno;
  71.  
  72. char *error_description();
  73.  
  74. static void copy_write_error_exit()
  75. {
  76.     MoveCursor(LINES, 0);
  77.     Raw(OFF);
  78.     printf(catgets(elm_msg_cat, ElmSet, ElmWriteCopyMessageFailed,
  79.         "\nWrite in copy_message failed\n"));
  80.     dprint(1, (debugfile,"\n*** Fprint failed on copy_message;\n"));
  81.     rm_temps_exit();
  82. }
  83.  
  84. copy_message(prefix, 
  85.          dest_file, 
  86.          cm_options)
  87. char *prefix;
  88. FILE *dest_file;
  89. int cm_options;
  90. {
  91.     /** Copy current message to destination file, with optional 'prefix' 
  92.         as the prefix for each line.  If remove_header is true, it will 
  93.         skip lines in the message until it finds the end of header line...
  94.         then it will start copying into the file... If remote is true
  95.         then it will append "remote from <hostname>" at the end of the
  96.         very first line of the file (for remailing) 
  97.  
  98.         If "forwarding" is true then it'll do some nice things to
  99.         ensure that the forwarded message looks pleasant; e.g. remove
  100.         stuff like ">From " lines and "Received:" lines.
  101.  
  102.         If "update_status" is true then it will write a new Status:
  103.         line at the end of the headers.  It never copies an existing one.
  104.  
  105.         If "decode" is true, prompt for key if the message is encrypted,
  106.         else just copy it as it is.
  107.     **/
  108.  
  109.     char buffer[SLEN];
  110.     register struct header_rec *current_header = headers[current-1];
  111.     register int  lines, front_line, next_front,
  112.           in_header = 1, first_line = TRUE, ignoring = FALSE;
  113.     int remove_header = cm_options & CM_REMOVE_HEADER;
  114.     int remote = cm_options & CM_REMOTE;
  115.     int update_status = cm_options & CM_UPDATE_STATUS;
  116.     int remail = cm_options & CM_REMAIL;
  117.     int decode = cm_options & CM_DECODE;
  118.     int    end_header = 0;
  119.     int sender_added = 0;
  120.     int crypted = 0;
  121.     int bytes_seen = 0;
  122.     int buf_len, err;
  123.  
  124.       /** get to the first line of the message desired **/
  125.  
  126.     if (fseek(mailfile, current_header->offset, 0) == -1) {
  127.        dprint(1, (debugfile, 
  128.         "ERROR: Attempt to seek %d bytes into file failed (%s)",
  129.         current_header->offset, "copy_message"));
  130.        error1(catgets(elm_msg_cat, ElmSet, ElmSeekFailed,
  131.          "ELM [seek] failed trying to read %d bytes into file."),
  132.          current_header->offset);
  133.        return;
  134.     }
  135.  
  136.     /* how many lines in message? */
  137.  
  138.     lines = current_header->lines;
  139.  
  140.     /* set up for forwarding just in case... */
  141.  
  142.     if (forwarding)
  143.       remove_header = FALSE;
  144.  
  145.     if (current_header->encrypted && decode) {
  146.     getkey(OFF);
  147.     }
  148.  
  149.     /* now while not EOF & still in message... copy it! */
  150.  
  151.     next_front = TRUE;
  152.  
  153.     while (lines) {
  154.       if ((buf_len = mail_gets(buffer, SLEN, mailfile)) == 0)
  155.         break;
  156.  
  157.       bytes_seen += buf_len;
  158.       front_line = next_front;
  159.  
  160.       if(buffer[buf_len - 1] == '\n') {
  161.     lines--;    /* got a full line */
  162.     next_front = TRUE;
  163.       }
  164.       else
  165.     next_front = FALSE;
  166.       
  167.       if (front_line && ignoring)
  168.     ignoring = whitespace(buffer[0]);
  169.  
  170.       if (ignoring)
  171.     continue;
  172.  
  173. #ifdef MMDF
  174.       if ((cm_options & CM_MMDF_HEAD) && strcmp(buffer, MSG_SEPARATOR) == 0)
  175.     continue;
  176. #endif /* MMDF */
  177.  
  178.       /* are we still in the header? */
  179.  
  180.       if (in_header && front_line) {
  181.     if (buf_len < 2) {
  182.       in_header = 0;
  183.       end_header = -1;
  184.       if (remail && !sender_added) {
  185.         if (fprintf(dest_file, "%sSender: %s\n", prefix, username) == EOF) {
  186.           copy_write_error_exit();
  187.         }
  188.       }
  189.     }
  190.     else if (!isspace(*buffer)
  191.           && index(buffer, ':') == NULL
  192. #ifdef MMDF
  193.           && strcmp(buffer, MSG_SEPARATOR) != 0
  194. #endif /* MMDF */
  195.         ) {
  196.       in_header = 0;
  197.       end_header = 1;
  198.       if (remail && !sender_added) {
  199.         if (fprintf(dest_file, "%sSender: %s\n", prefix, username) == EOF) {
  200.           copy_write_error_exit();
  201.         }
  202.       }
  203.     } else if (in_header && remote && header_cmp(buffer, "Sender", NULL)) {
  204.       if (remail)
  205.         if (fprintf(dest_file, "%sSender: %s\n", prefix, username) == EOF) {
  206.           copy_write_error_exit();
  207.         }
  208.       sender_added = TRUE;
  209.       continue;
  210.     }
  211.     if (end_header) {
  212.       if (update_status) {
  213.           if (isoff(current_header->status, NEW)) {
  214.         if (ison(current_header->status, UNREAD)) {
  215.           if (fprintf(dest_file, "%sStatus: O\n", prefix) == EOF) {
  216.             copy_write_error_exit();
  217.           }
  218.         } else    /* read */
  219. #ifdef BSD
  220.           if (fprintf(dest_file, "%sStatus: OR\n", prefix) == EOF) {
  221. #else
  222.           if (fprintf(dest_file, "%sStatus: RO\n", prefix) == EOF) {
  223. #endif
  224.             copy_write_error_exit();
  225.           }
  226.         update_status = FALSE; /* do it only once */
  227.           }    /* else if NEW - indicate NEW with no Status: line. This is
  228.          * important if we resync a mailfile - we don't want
  229.          * NEW status lost when we copy each message out.
  230.          * It is the responsibility of the function that calls
  231.          * this function to unset NEW as appropriate to its
  232.          * reason for using this function to copy a message
  233.          */
  234.  
  235.         /*
  236.          * add the missing newline for RFC 822
  237.          */
  238.           if (end_header > 0) {
  239.         /* add the missing newline for RFC 822 */
  240.         if (fprintf(dest_file, "\n") == EOF) {
  241.           copy_write_error_exit();
  242.         }
  243.           }
  244.       }
  245.     }
  246.       }
  247.  
  248.       if (in_header) {
  249.     /* Process checks while in header area */
  250.  
  251.     if (remove_header) {
  252.       ignoring = TRUE;
  253.       continue;
  254.     }
  255.  
  256.     /* add remote on to front? */
  257.     if (first_line && remote) {
  258.       no_ret(buffer);
  259. #ifndef MMDF
  260.       if (fprintf(dest_file, "%s%s remote from %s\n",
  261.           prefix, buffer, hostname) == EOF) {
  262.         copy_write_error_exit();
  263.       }
  264. #else
  265.       if (first_word(buffer, "From ")) {
  266.         if (fprintf(dest_file, "%s%s remote from %s\n",
  267.             prefix, buffer, hostname) == EOF) {
  268.         copy_write_error_exit();
  269.         }
  270.       } else {
  271.         if (fprintf(dest_file, "%s%s\n", prefix, buffer) == EOF) {
  272.         copy_write_error_exit();
  273.         }
  274.       }
  275. #endif /* MMDF */
  276.       first_line = FALSE;
  277.       continue;
  278.     }
  279.  
  280.     if (!forwarding) {
  281.       if(! header_cmp(buffer, "Status", NULL)) {
  282.         if (fprintf(dest_file, "%s%s", prefix, buffer) == EOF) {
  283.           copy_write_error_exit();
  284.           }
  285.         continue;
  286.       } else {
  287.         ignoring = TRUE;
  288.         continue;    /* we will output a new Status: line later, if desired. */
  289.       }
  290.     }
  291.     else { /* forwarding */
  292.  
  293.       if (header_cmp(buffer, "Received", NULL   ) ||
  294.           first_word_nc(buffer, ">From"         ) ||
  295.           header_cmp(buffer, "Status", NULL     ) ||
  296.           header_cmp(buffer, "Return-Path", NULL))
  297.           ignoring = TRUE;
  298.       else
  299.         if (remail && header_cmp(buffer, "To", NULL)) {
  300.           if (fprintf(dest_file, "%sOrig-%s", prefix, buffer) == EOF) {
  301.         copy_write_error_exit();
  302.           }
  303.         } else {
  304.           if (fprintf(dest_file, "%s%s", prefix, buffer) == EOF) {
  305.         copy_write_error_exit();
  306.           }
  307.         }
  308.     }
  309.       }
  310.       else { /* not in header */
  311.         /* Process checks that occur after the header area */
  312.  
  313.     /* perform encryption checks */
  314.     if (buffer[0] == '[' && decode) {
  315.         if (!strncmp(buffer, START_ENCODE, strlen(START_ENCODE))) {
  316.             crypted = ON;
  317.         } else if (!strncmp(buffer, END_ENCODE, strlen(END_ENCODE))) {
  318.             crypted = OFF;
  319.         } else if (crypted) {
  320.             no_ret(buffer);
  321.             encode(buffer);
  322.             strcat(buffer, "\n");
  323.         }
  324.     } else if (crypted) {
  325.         no_ret(buffer);
  326.         encode(buffer);
  327.         strcat(buffer, "\n");
  328.     }
  329.  
  330.  
  331. #ifndef MMDF
  332. #ifndef DONT_ESCAPE_MESSAGES
  333.     if(first_word(buffer, "From ") && (real_from(buffer, NULL)) &&
  334.        current_header->content_length <= bytes_seen) {
  335.       /* If we have a content-length > bytes_seen and there is lines left
  336.       ** this is probably a From line that is part of the body, as an
  337.       ** included message. A simple heuristic test.
  338.       */
  339.       dprint(1, (debugfile,
  340.          "\n*** Internal Problem...Tried to add the following;\n"));
  341.       dprint(1, (debugfile,
  342.          "  '%s'\nto output file (copy_message) ***\n", buffer));
  343.       break;    /* STOP NOW! */
  344.     }
  345. #endif /* DONT_ESCAPE_MESSAGES */
  346. #endif /* MMDF */
  347.  
  348.     err = fprintf(dest_file, "%s", prefix);
  349.     if (err != EOF)
  350.       err = fwrite(buffer, 1, buf_len, dest_file);
  351.     if (err != buf_len) {
  352.       copy_write_error_exit();
  353.     }
  354.       }
  355.     }
  356. #ifndef MMDF
  357.     if (buf_len + strlen(prefix) > 1)
  358.     if (fprintf(dest_file, "\n") == EOF) {    /* blank line to keep mailx happy *sigh* */
  359.       copy_write_error_exit();
  360.     }
  361. #endif /* MMDF */
  362. }
  363.  
  364. static struct stat saved_buf;
  365. static char saved_fname[SLEN];
  366.  
  367. int
  368. save_file_stats(fname)
  369. char *fname;
  370. {
  371.     /* if fname exists, save the owner, group, mode and filename.
  372.      * otherwise flag nothing saved. Return 0 if saved, else -1.
  373.      */
  374.  
  375.     if(stat(fname, &saved_buf) != -1) {
  376.       (void)strcpy(saved_fname, fname);
  377.       dprint(2, (debugfile,
  378.         "** saved stats for file owner = %d group = %d mode = %o %s **\n",
  379.         saved_buf.st_uid, saved_buf.st_gid, saved_buf.st_mode, fname));
  380.       return(0);
  381.     }
  382.     dprint(2, (debugfile,
  383.       "** couldn't save stats for file %s [errno=%d] **\n",
  384.       fname, errno));
  385.     return(-1);
  386.  
  387. }
  388.  
  389. restore_file_stats(fname)
  390. char *fname;
  391. {
  392.     /* if fname matches the saved file name, set the owner and group
  393.      * of fname to the saved owner, group and mode,
  394.      * else to the userid and groupid of the user and to 700.
  395.      * Return    -1 if the  either mode or owner/group not set
  396.      *        0 if the default values were used
  397.      *        1 if the saved values were used
  398.      */
  399.  
  400.     int old_umask, i, new_mode, new_owner, new_group, ret_code;
  401.  
  402.  
  403.     new_mode = 0600;
  404.     new_owner = userid;
  405.     new_group = groupid;
  406.     ret_code = 0;
  407.  
  408.     if(strcmp(fname, saved_fname) == 0) {
  409.       new_mode = saved_buf.st_mode;
  410.       new_owner = saved_buf.st_uid;
  411.       new_group = saved_buf.st_gid;
  412.       ret_code = 1;
  413.     }
  414.     dprint(2, (debugfile, "** %s file stats for %s **\n",
  415.       (ret_code ? "restoring" : "setting"), fname));
  416.  
  417.     old_umask = umask(0);
  418.     if((i = chmod(fname, new_mode & 0777)) == -1)
  419.       ret_code = -1;
  420.  
  421.     dprint(2, (debugfile, "** chmod(%s, %.3o) returns %d [errno=%d] **\n",
  422.         fname, new_mode & 0777, i, errno));
  423.  
  424.     (void) umask(old_umask);
  425.  
  426. #ifdef    BSD
  427.     /*
  428.      * Chown is restricted to root on BSD unix
  429.      */
  430.     (void) chown(fname, new_owner, new_group);
  431. #else
  432.     if((i = chown(fname, new_owner, new_group)) == -1)
  433.       ret_code = -1;
  434.  
  435.     dprint(2, (debugfile, "** chown(%s, %d, %d) returns %d [errno=%d] **\n",
  436.            fname, new_owner, new_group, i, errno));
  437. #endif
  438.  
  439.     return(ret_code);
  440.  
  441. }
  442.  
  443. /** and finally, here's something for that evil trick: site hiding **/
  444.  
  445. #ifdef SITE_HIDING
  446.  
  447. int
  448. is_a_hidden_user(specific_username)
  449. char *specific_username;
  450. {
  451.     /** Returns true iff the username is present in the list of
  452.        'hidden users' on the system.
  453.     **/
  454.     
  455.     FILE *hidden_users;
  456.     char  buffer[SLEN];
  457.  
  458.         /* 
  459.     this line is deliberately inserted to ensure that you THINK
  460.     about what you're doing, and perhaps even contact the author
  461.     of Elm before you USE this option...
  462.         */
  463.  
  464.     if ((hidden_users = fopen (HIDDEN_SITE_USERS,"r")) == NULL) {
  465.       dprint(1, (debugfile,
  466.           "Couldn't open hidden site file %s [%s]\n",
  467.           HIDDEN_SITE_USERS, error_description(errno)));
  468.       return(FALSE);
  469.     }
  470.  
  471.     while (fscanf(hidden_users, "%s", buffer) != EOF)
  472.       if (strcmp(buffer, specific_username) == 0) {
  473.         dprint(3, (debugfile, "** Found user '%s' in hidden site file!\n",
  474.             specific_username));
  475.         fclose(hidden_users);
  476.         return(TRUE);
  477.       }
  478.  
  479.     fclose(hidden_users);
  480.     dprint(3, (debugfile, 
  481.         "** Couldn't find user '%s' in hidden site file!\n",
  482.         specific_username));
  483.  
  484.     return(FALSE);
  485. }
  486.  
  487. #endif
  488.